/****************************************************************************************
 *       Filename:  gt911.c
 *    Description:  gt911 driver
 *        Version:  1.0
 *        Created:  08/22/2022 17:59:30 AM
 *         Author:  andid (), andid@sntu.net.cn
 *        Company:  ranzgou co,ltd
 ****************************************************************************************/

#include <stdio.h>
#include <stdbool.h>
#include "gt911.h"
#include "esp_err.h"
#include "driver/i2c.h"

#define I2C_MASTER_NUM              0                   
#define I2C_MASTER_FREQ_HZ          100000             
#define I2C_MASTER_TIMEOUT_MS       1000

static gtdev_t tp_point;
const uint16_t tp_point_tbl[5] = 
{
	GT9x_TP1,
	GT9x_TP2,
	GT9x_TP3,
	GT9x_TP4,
	GT9x_TP5
};

static int gt911_write_regs(uint16_t reg, uint8_t *data, uint8_t len)
{
	uint8_t regl = reg&0xff;
	uint8_t regh = (reg>>8)&0xff;
	uint8_t wbuf[128] = {regh, regl};
	for(uint8_t i = 0;i<len;i++)
	{
		wbuf[i+2] = data[i];
	}
	len += 2;
	return i2c_master_write_to_device(I2C_MASTER_NUM, GT9x_ADDR,\
			wbuf, len, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}

static int gt911_read_regs(uint16_t reg, uint8_t *data, uint8_t len)
{
	uint8_t regl = reg&0xff;
	uint8_t regh = (reg>>8)&0xff;
	uint8_t rbuf[2] = {regh, regl};
	return i2c_master_write_read_device(I2C_MASTER_NUM, GT9x_ADDR, rbuf, 2,\
			            data, len, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}

bool gt911_read_points(int16_t *x, int16_t *y)
{
	uint8_t touch_state, touch_num, temp, temp_state, buf[5];
	
	gt911_read_regs(GT9x_GSTID, &touch_state, 1);
	touch_num = touch_state & 0xf;
	if((touch_state & 0x80) && touch_num < 6)
	{
		temp = 0;
		gt911_write_regs(GT9x_GSTID, &temp, 1);
	}
	if(touch_num && (touch_num < 6))
	{
		temp = 0xff << touch_num;
		temp_state = tp_point.state;
		tp_point.state = (~temp) | TP_PRESS;
		tp_point.x[4] = tp_point.x[0];
		tp_point.y[4] = tp_point.y[0];
		for(uint8_t i=0;i<touch_num;i++)
		{
			if(tp_point.state & (1<<i))
			{
				gt911_read_regs(tp_point_tbl[i], buf, 4);
				tp_point.x[i] = ((uint16_t)buf[1]<<8) + buf[0];
				tp_point.y[i] = ((uint16_t)buf[3]<<8) + buf[2];
			}
		}
		if(tp_point.x[0] > 800 || tp_point.y[0] > 480)
		{
			tp_point.x[0] = tp_point.x[4];
			tp_point.y[0] = tp_point.y[4];
			touch_state = 0x80;
			tp_point.state = temp_state;
		}
	}

	if((touch_state & 0x8f) == 0x80)
	{
		tp_point.x[0] = 0xffff;
		tp_point.y[0] = 0xffff;
		tp_point.state &= ~TP_PRESS;
	}

	*x = tp_point.x[0];
	*y = tp_point.y[0];

	return (tp_point.state & TP_PRESS) ? true : false;
}

void gt911_init(void)
{
	uint8_t buf[5] = {2, 0, 0, 0, 0};
	gt911_write_regs(GT9x_CTRL, buf, 1);//soft reset
	gt911_read_regs(GT9x_PID, buf, 4);
	printf("GT911 PRODUCT ID: %s\n", buf);
}

